package gui;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.SystemTray;
import java.awt.Toolkit;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTabbedPane;
import java.net.URL;
import java.util.ArrayList;

import app.AppInterface;
import serverClient.ConfigChangeObserver;
import serverClient.GuiChangeObserver;
import log.LogToGuiObserver;

public class Gui implements GuiInterface, GuiObserver, GuiChangeObserver, ConfigChangeObserver, LogToGuiObserver {

	private final boolean DEBUG = false;

	private String version;
	private AppInterface app;
	private JTabbedPane tabs;
	private GuiSync syncTab;
	private GuiConfig configTab;
	private GuiLog logTab;
	private GuiCredits creditsTab;
	private GuiStatusBar statusBar;
	private GuiTray guiTray;

	private JFrame frame;

	public Gui(String version, AppInterface app) {
		this.version = version;
		this.app = app;
	}

	public void initGuiComponents() {

		if(DEBUG) System.out.println("Init GUI");

		GuiSkinUtilities.pickSkin(app.getSkinType());

		// Adds a frame
		frame = new JFrame("Sync IT");

		// Sets the Icon image
		ArrayList<Image> imageList = new ArrayList<Image>();
		URL imgURL = ClassLoader.getSystemResource("skin/SyncITIcon.gif");
		Image image = Toolkit.getDefaultToolkit().getImage(imgURL);
		imageList.add(image);
		imgURL = ClassLoader.getSystemResource("skin/SyncITLogo.gif");
		image = Toolkit.getDefaultToolkit().getImage(imgURL);
		imageList.add(image);
		frame.setIconImages(imageList);

		// Initializes JPanels
		syncTab = new GuiSync(app, this);
		configTab = new GuiConfig(app, this);
		logTab = new GuiLog(app);
		creditsTab = new GuiCredits(version);
		statusBar = new GuiStatusBar();
		guiTray = new GuiTray(frame, app, syncTab);

		// Adds the different tabs
		tabs = new JTabbedPane();
		tabs.addTab("Sync", null, syncTab, "Sync tab");
		tabs.addTab("Config", null, configTab, "Config tab");
		tabs.addTab("Log", null, logTab, "Log tab");
		tabs.addTab("Credits", null, creditsTab, "Credit tab");

		// Sets mnemonics to the tabs
		tabs.setMnemonicAt(0, 'Y');
		tabs.setMnemonicAt(1, 'N');
		tabs.setMnemonicAt(2, 'G');
		tabs.setMnemonicAt(3, 'E');

		// Sets up the frame
		frame.getContentPane().add(statusBar, BorderLayout.SOUTH);
		frame.getContentPane().add(tabs);

		//frame.pack();
		frame.setSize(new Dimension(341, 454));
		frame.setVisible(app.getVisibleGui());
	}


	// Load configurations to the GUI
	public void loadConfigToGui() {

		if(DEBUG) System.out.println("Load config to GUI");

		logTab.setGuiLog();
		configTab.setGuiConf();
		syncTab.setGuiSync();
		if( SystemTray.isSupported() ) {
			guiTray.setGuiTray();
		}

		// Gives a warning if you start the program for the first time
		// Determines if you start for the first time by checking if there exists an old configuration file
		if(app.getFirstStart()) {
			JOptionPane.showMessageDialog(null, "Remember to syncronize the clocks on the\n" +
					"computers where you are running this program!",
					" Sync the clock!",
					JOptionPane.INFORMATION_MESSAGE);
		}
	}

	public void initGuiObservers() {
		app.addGuiChangeObserver(this);
		app.addConfigChangeObserver(this);
		app.addLogToGuiObserver(this);
	}


	
	// GuiObserver methods //
	
	public void setAutoSync(boolean autoSync) {
		if(autoSync) {
			syncTab.startAutoSync();
		}
		else {
			syncTab.stopAutoSync();
		}
	}

	public void setLocalSync(boolean localSync) {
		// Enable/disable GUI components
		if(localSync) {
			configTab.showAutoSync(true);
			if(SystemTray.isSupported()) {
				guiTray.showSyncItem(true);
				guiTray.showCancelItem(true);
			}
		}
		else if(!localSync && !app.getStartListen()) {
			configTab.showAutoSync(false);
			configTab.setAutoSyncStatus(false);
			if(SystemTray.isSupported()) {
				guiTray.showSyncItem(false);
				guiTray.showCancelItem(false);
			}
		}
	}

	// To be able to enable or disable GUI components in other panels
	public void enableOtherGuiComponents(boolean enable) {
		// Enable/disable GUI components
		configTab.showListenPortLabel(!enable);
		configTab.showListenPort(!enable);
		if(enable) {
			configTab.showAutoSync(true);
			if(SystemTray.isSupported()) {
				guiTray.showSyncItem(true);
				guiTray.showCancelItem(true);
			}
		}
		else if(!enable && !app.getLocalSync()) {
			configTab.showAutoSync(false);
			configTab.setAutoSyncStatus(false);
			if(SystemTray.isSupported()) {
				guiTray.showSyncItem(false);
				guiTray.showCancelItem(false);
			}
		}
	}

	// To be able to enable or disable the listen port field
	public void enableListenPortField(boolean enable) {
		// Enable/disable listen port
		configTab.showListenPortLabel(enable);
		configTab.showListenPort(enable);
	}



	// GuiChangeObserver methods //

	public void enableGuiComponents(boolean show) {
		syncTab.enableGuiComponents(show);
		configTab.enableGuiComponents(show);
		logTab.enableGuiComponents(show);
		if( SystemTray.isSupported() ) {
			guiTray.enableGuiComponents(show);
		}
	}

	public void initFileTransfer(int noOfFiles, long totalOfBytes) {
		statusBar.initFileTransfer(noOfFiles, totalOfBytes);
		guiTray.initFileTransfer(noOfFiles, 0);
	}

	public void byteProgressUpdate(int len) {
		statusBar.byteProgressUpdate(len);
	}

	public void fileInProgress() {
		statusBar.fileInProgress();
		guiTray.fileInProgress();
	}

	public void filesTransferFinished() {
		statusBar.filesTransferFinished();
	}


	// GuiChangeObserver methods //

	public void changeConfigSyncMode(String syncMode) {
		configTab.changeConfigSyncMode(syncMode);
	}

	public void changeConfigIncludeHidden(boolean includeHidden) {
		configTab.changeConfigIncludeHidden(includeHidden);
	}

	public void changeConfigUseExactTime(boolean useExactTime) {
		configTab.changeConfigUseExactTime(useExactTime);
	}


	// LogToGuiObserver methods //

	public void connectionStatusChanged(String message) {
		syncTab.connectionStatusChanged(message);
		statusBar.connectionStatusChanged(message);
	}

	public void connectionStatusWarning(String message) {
		syncTab.connectionStatusWarning(message);
		logTab.connectionStatusWarning(message);
		statusBar.connectionStatusWarning(message);
		guiTray.connectionStatusWarning(message);
	}

	public void transferMessage(String message) {
		logTab.transferMessage(message);
		statusBar.transferMessage(message);
		guiTray.transferMessage(message);
	}

}
